package com.elric.mall.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.elric.mall.common.enums.ExcelDataType;
import com.elric.mall.common.utils.ImportExcelUtil;
import com.elric.mall.dto.ProgrammeManageDto;
import com.elric.mall.dto.ProgrammeProjectDto;
import com.elric.mall.dto.ProgrammeProjectExportDto;
import com.elric.mall.dto.ProgrammeProjectImportDto;
import com.elric.mall.enums.ImportType;
import com.elric.mall.mapper.InvestCalcMapper;
import com.elric.mall.mapper.PlanProjectMapper;
import com.elric.mall.mapper.ProgrammeProjectMapper;
import com.elric.mall.mapper.ProjectManageMapper;
import com.elric.mall.model.*;
import com.elric.mall.model.Dictionary;
import com.elric.mall.service.DictionaryService;
import com.elric.mall.service.ProgrammeProjectService;
import com.elric.mall.service.TaskService;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 实现功能：计划项目实现层
 *
 * @author 作者[Yuxuan.he]
 * @version 1.0.00  2021-09-16 11:21
 */
@Service
public class ProgrammeProjectServiceImpl implements ProgrammeProjectService {
    @Autowired
    private ProgrammeProjectMapper programmeProjectMapper;

    @Autowired
    private PlanProjectMapper planProjectMapper;

    @Autowired
    private InvestCalcMapper investCalcMapper;

    @Autowired
    private ProjectManageMapper projectManageMapper;

    @Autowired
    private DictionaryService dictionaryService;

    @Autowired
    private TaskService taskService;

    private static final String INVEST_CALC_TYPE = "PROGRAM";
    private static final String VALIDATE_STATUS_SUCCESS = "SUCCESS";
    private static final String VALIDATE_STATUS_FAIL = "ERROR";
    private static final int MAX_COMMIT_COUNT = 200;

    // 项目编码固定长度
    private static final Integer PROJECT_CODE_LENGTH = 16;

    // 项目编码固定结尾字符串
    private static final String PROJECT_CODE_END_WITH = "X";

    private void initProjectInfo(ProgrammeProject programmeProject, UmsAdmin umsAdmin) {
        programmeProject.setId(IdUtil.fastUUID());
        programmeProject.setCreateDate(new DateTime());
        programmeProject.setCreatorId(umsAdmin.getId());
        programmeProject.setCreatorName(umsAdmin.getUsername());
    }

    private void initInvestCalcInfo(InvestCalc investCalc, UmsAdmin umsAdmin) {
        investCalc.setId(IdUtil.fastUUID());
        investCalc.setCreateDate(new DateTime());
        investCalc.setCreatorId(umsAdmin.getId());
        investCalc.setCreatorName(umsAdmin.getUsername());
        investCalc.setType(INVEST_CALC_TYPE);
    }

    @Override
    public int create(ProgrammeProject programmeProject) {
        programmeProject.setId(IdUtil.fastUUID());
        return programmeProjectMapper.insert(programmeProject);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int update(ProgrammeManageDto programmeProject) {
        ProjectManage projectManage = projectManageMapper.selectByProjectKey(programmeProject.getId());
        if (!Objects.isNull(projectManage)) {
            projectManage.setValidateMessage(programmeProject.getValidateMessage());
            projectManage.setValidateStatus(programmeProject.getValidateStatus());
            projectManageMapper.updateByPrimaryKey(projectManage);
        }
        return programmeProjectMapper.updateByPrimaryKeySelective(programmeProject);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public ProgrammeProjectDto save(ProgrammeProjectDto dto, UmsAdmin umsAdmin) {
        ProgrammeProject programmeProject = new ProgrammeProject();
        BeanUtils.copyProperties(dto, programmeProject);
        if (StrUtil.isNotBlank(programmeProject.getId())){
            programmeProjectMapper.updateByPrimaryKeySelective(programmeProject);

            //删除所有投资匡算信息
            InvestCalcExample investCalcExample = new InvestCalcExample();
            investCalcExample.createCriteria().andProjectCodeEqualTo(programmeProject.getId());
            investCalcMapper.deleteByExample(investCalcExample);
        } else {
            initProjectInfo(programmeProject, umsAdmin);
            programmeProjectMapper.insert(programmeProject);
        }

        // 插入投资匡算信息
        List<InvestCalc> calcs = dto.getInvestCalcList();
        if (CollectionUtil.isNotEmpty(calcs)){
            calcs.forEach(c -> {
                initInvestCalcInfo(c, umsAdmin);
                c.setProjectCode(programmeProject.getId());
            });
            investCalcMapper.insertBatch(calcs);
        }
        return dto;
    }

    @Override
    public ProgrammeProjectDto findById(String id) {
        ProgrammeProjectDto dto = new ProgrammeProjectDto();
        ProgrammeProject programmeProject = programmeProjectMapper.selectByPrimaryKey(id);
        BeanUtils.copyProperties(programmeProject, dto);
        // 查询投资匡算信息
        InvestCalcExample investCalcExample = new InvestCalcExample();
        investCalcExample.createCriteria().andProjectCodeEqualTo(programmeProject.getId());
        List<InvestCalc> investCalcs = investCalcMapper.selectByExample(investCalcExample);
        dto.setInvestCalcList(investCalcs);
        return dto;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int delete(String id) {
        ProgrammeProject programmeProject = programmeProjectMapper.selectByPrimaryKey(id);
        // 删除投资匡算信息
        InvestCalcExample investCalcExample = new InvestCalcExample();
        investCalcExample.createCriteria().andProjectCodeEqualTo(id);
        investCalcMapper.deleteByExample(investCalcExample);
        if (StrUtil.isNotBlank(programmeProject.getTaskUnitId())) {
            // 更新任务信息
            taskService.updateTaskInfo(programmeProject.getTaskUnitId());
        }
        return programmeProjectMapper.deleteByPrimaryKey(id);
    }

    private ProgrammeProjectExample getExampleByModel(ProgrammeProject programmeProject) {
        ProgrammeProjectExample example = new ProgrammeProjectExample();
        ProgrammeProjectExample.Criteria criteria = example.createCriteria();
        if(StrUtil.isNotBlank(programmeProject.getXmmc())) {
            criteria.andXmmcLike("%"+programmeProject.getXmmc()+ "%");
        }
        if(StrUtil.isNotBlank(programmeProject.getXmdm())) {
            criteria.andXmdmLike("%"+programmeProject.getXmdm()+ "%");
        }
        if(StrUtil.isNotBlank(programmeProject.getCjdw())) {
            criteria.andCjdwLike("%"+programmeProject.getCjdw()+ "%");
        }
        if(StrUtil.isNotBlank(programmeProject.getTbdw())) {
            criteria.andTbdwLike("%"+programmeProject.getTbdw()+ "%");
        }
        if(StrUtil.isNotBlank(programmeProject.getSplx())) {
            criteria.andSplxEqualTo(programmeProject.getSplx());
        }
        if (StrUtil.isNotBlank(programmeProject.getTaskUnitId())) {
            criteria.andTaskUnitIdEqualTo(programmeProject.getTaskUnitId());
        }
        if (CollectionUtil.isNotEmpty(programmeProject.getGcList())) {
            criteria.andGcmcIn(programmeProject.getGcList());
        }
        if (CollectionUtil.isNotEmpty(programmeProject.getJqList())) {
            criteria.andJqmcIn(programmeProject.getJqList());
        }
        return example;
    }

    @Override
    public List<ProgrammeProject> list(Integer pageSize, Integer pageNum, ProgrammeProject programmeProject) {
        PageHelper.startPage(pageNum, pageSize);
        ProgrammeProjectExample example = getExampleByModel(programmeProject);
        return programmeProjectMapper.selectByExampleWithBLOBs(example);
    }

    @Override
    public List<ProgrammeManageDto> findManageByPage(Integer pageSize, Integer pageNum, ProgrammeManageDto programmeProject) {
        PageHelper.startPage(pageNum, pageSize);
        return programmeProjectMapper.selectManageByModel(programmeProject);
    }

    @Override
    public Map<String, Object> manageStatistics(ProgrammeManageDto programmeProject) {
        List<ProgrammeManageDto> list = programmeProjectMapper.selectManageByModel(programmeProject);
        int total = 0;
        long success = 0L;
        long unchecked = 0L;
        if (CollectionUtil.isNotEmpty(list)) {
            total = list.size();
            success = list.stream().filter(p -> StrUtil.equals(p.getValidateStatus(), VALIDATE_STATUS_SUCCESS)).count();
            unchecked = list.stream().filter(p -> StrUtil.isBlank(p.getValidateStatus())).count();
        }
        Map<String, Object> map = new HashMap<>();
        map.put("total", total);
        map.put("success", success);
        map.put("unchecked", unchecked);
        return map;
    }

    /**
     * 初始化数据导出dto清单
     * @return
     */
    private List<ProgrammeProjectExportDto> initExportHeader() {
        List<ProgrammeProjectExportDto> list = new ArrayList<>();
        XSSFColor xssfColor = new XSSFColor(new java.awt.Color(255, 255, 255));
        // 抬头左上角"附件1"
        ProgrammeProjectExportDto title1 = new ProgrammeProjectExportDto();
        title1.setNum("附件1");
        title1.setStartNum(0);
        title1.setEndNum(1);
        title1.setRegion(true);
        title1.setDataType(ExcelDataType.header.name());
        title1.setFillForegroundColor(xssfColor);
        title1.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        title1.setAlignment(HorizontalAlignment.LEFT);
        title1.setFontSize((short) 14);
        title1.setCellHeight((short) 400);
        title1.setBorder(false);
        title1.setFontName("黑体");
        list.add(title1);

        // 抬头中间第二行"项目清单标题"
        ProgrammeProjectExportDto title2 = new ProgrammeProjectExportDto();
        title2.setNum("新上项目台账");
        title2.setAlignment(HorizontalAlignment.CENTER);
        title2.setStartNum(0);
        title2.setEndNum(13);
        title2.setRegion(true);
        title2.setDataType(ExcelDataType.header.name());
        title2.setFillForegroundColor(xssfColor);
        title2.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        title2.setFontSize((short) 24);
        title2.setCellHeight((short) 750);
        title2.setBorder(false);
        title2.setFontName("黑体");
        list.add(title2);

        // 抬头单位"万元"
        ProgrammeProjectExportDto title3 = new ProgrammeProjectExportDto();
        title3.setSpqx("金额单位：万元");
        title3.setStartNum(8);
        title3.setEndNum(13);
        title3.setRegion(true);
        title3.setDataType(ExcelDataType.header.name());
        title3.setFillForegroundColor(xssfColor);
        title3.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        title3.setFontSize((short) 10);
        title3.setCellHeight((short) 300);
        title3.setAlignment(HorizontalAlignment.RIGHT);
        title3.setBorder(false);
        title3.setFontName("楷体");
        list.add(title3);
        return list;
    }

    /**
     * 根据工程、集群信息对计划项目进行排序
     * @param dtos
     * @return
     */
    private List<ProgrammeProjectExportDto> formatByProjectAndGroup(List<ProgrammeProjectExportDto> dtos) {
        List<ProgrammeProjectExportDto> list = initExportHeader();
        if (CollectionUtil.isNotEmpty(dtos)){
            // 分别查询项目、集群信息list
            List<Dictionary> projects = dictionaryService.findByType("PROJECT_NAME");
            List<Dictionary> groups = dictionaryService.findByType("GROUP_NAME");
            projects.forEach(p -> {
                AtomicInteger programmeNum = new AtomicInteger(1);
                // 找出当前工程下的计划信息
                List<ProgrammeProjectExportDto> matchProjectDtos = dtos.stream().filter(d -> StrUtil.equals(d.getGcmc(), p.getName())).collect(Collectors.toList());
                // 只添加有对应工程信息的数据
                if (CollectionUtil.isNotEmpty(matchProjectDtos)) {
                    ProgrammeProjectExportDto projectDto = new ProgrammeProjectExportDto();
                    int proNum = Objects.isNull(p.getOrderNum())?0: p.getOrderNum();
                    projectDto.setNum(Convert.numberToChinese(proNum, false));
                    // 设置合并列状态
                    projectDto.setRegion(true);
                    projectDto.setStartNum(1);
                    projectDto.setEndNum(2);
                    projectDto.setCjdw(p.getName());
                    list.add(projectDto);
                    // 筛选出当前工程下的集群信息（当前工程下的计划包含该的集群即为该工程下的集群）
                    List<Dictionary> matchGroups = groups.stream()
                            .filter(g -> matchProjectDtos.stream().anyMatch(mp -> StrUtil.equals(g.getName(), mp.getJqmc())))
                            .collect(Collectors.toList());
                    matchGroups.stream().forEach(mg -> {
                        ProgrammeProjectExportDto groupDto = new ProgrammeProjectExportDto();
                        int groupNum = Objects.isNull(mg.getOrderNum())?0: mg.getOrderNum();
                        groupDto.setNum("(" + Convert.numberToChinese(groupNum, false) + ")");
                        // 设置合并列状态
                        groupDto.setRegion(true);
                        groupDto.setStartNum(1);
                        groupDto.setEndNum(2);
                        groupDto.setCjdw(mg.getName());
                        // 添加集群合并列
                        list.add(groupDto);
                        // 将匹配到集群的计划信息添加到list中
                        matchProjectDtos.stream()
                                .filter(mp -> StrUtil.equals(mp.getJqmc(), mg.getName()))
                                .forEach(mp -> {
                                    // 重新编号
                                    mp.setNum(StrUtil.toString(programmeNum));
                                    programmeNum.getAndIncrement();
                                    list.add(mp);
                                });
                    });
                }
            });
        }
        return list;
    }

    @Override
    public List<ProgrammeProjectExportDto> findExportByModel(ProgrammeProject programmeProject) {
        ProgrammeProjectExample example = getExampleByModel(programmeProject);
        List<ProgrammeProject> projectList = programmeProjectMapper.selectByExampleWithBLOBs(example);

        List<InvestCalc> investCalcList = new ArrayList<>();

        if(CollectionUtil.isNotEmpty(projectList)){
            InvestCalcExample investCalcExample = new InvestCalcExample();
            investCalcExample.createCriteria()
                    .andProjectCodeIn(projectList.stream().map(ProgrammeProject::getId).collect(Collectors.toList()))
                    .andTypeEqualTo(INVEST_CALC_TYPE);
            investCalcList = investCalcMapper.selectByExample(investCalcExample);
        }

        final Integer[] index = {1};
        List<InvestCalc> finalInvestCalcList = investCalcList;
        List<ProgrammeProjectExportDto> dtoList = projectList.stream().map(p -> {
            ProgrammeProjectExportDto dto = new ProgrammeProjectExportDto();
            BeanUtils.copyProperties(p, dto);
            dto.setNum(Integer.toString(index[0]));
            // 获取投资相关金额
            BigDecimal tz2022 = finalInvestCalcList.stream()
                    .filter(i -> StrUtil.equals(p.getId(), i.getProjectCode())&&StrUtil.equals("2022年投资", i.getName()))
                    .findFirst().orElse(new InvestCalc()).getAmount();
            dto.setTz2022(tz2022);
            BigDecimal tz2023 = finalInvestCalcList.stream()
                    .filter(i -> StrUtil.equals(p.getId(), i.getProjectCode())&&StrUtil.equals("2023年及以后投资", i.getName()))
                    .findFirst().orElse(new InvestCalc()).getAmount();
            dto.setTz2023(tz2023);
            index[0]++;
            return dto;
        }).collect(Collectors.toList());
        return formatByProjectAndGroup(dtoList);
    }

    /**
     * 校验导入数据
     * @param excelEntities
     */
    private void validateImportData(List<ProgrammeProjectImportDto> excelEntities) {
        if (CollectionUtil.isNotEmpty(excelEntities)){
            List<PlanProject> planProjects = planProjectMapper.selectByExample(new PlanProjectExample());
            excelEntities.stream().forEach(e -> {
                List<String> errorList = new ArrayList<>();
                if (StrUtil.isNotBlank(e.getValidateMessage())){
                    errorList.add(e.getValidateMessage());
                }

                if (StrUtil.isBlank(e.getCjdw())) {
                    errorList.add("请填写【建设单位】字段");
                }
                if (StrUtil.isBlank(e.getXmmc())) {
                    errorList.add("请填写【项目名称】字段");
                }
                if (StrUtil.isBlank(e.getXmdm())) {
                    errorList.add("请填写【规划项目编码】字段");
                } else {
                    // 如果项目编码是以X、Y、Z结尾，则需要校验项目编码长度
                    String[] strs = { "X", "Y", "Z" };
                    boolean match = StrUtil.endWithAny(e.getXmdm(), strs);
                    int length = StrUtil.length(e.getXmdm());
                    if (match&&length != PROJECT_CODE_LENGTH) {
                        errorList.add("【规划项目编码】长度不为"+PROJECT_CODE_LENGTH+"位");
                    }

                    boolean matchPlan = planProjects.stream()
                            .anyMatch(p -> StrUtil.equals(StrUtil.sub(p.getXmdm(), 0, 12), StrUtil.sub(e.getXmdm(), 0, 12)));
                    if (!matchPlan){
                        errorList.add("未找到匹配的【规划项目编码】");
                    }
                }
                if (StrUtil.isBlank(e.getJsnr())) {
                    errorList.add("请填写【主要建设内容及使命任务】字段");
                }
                if (StrUtil.isBlank(e.getSpqx())) {
                    errorList.add("请填写【审批权限】字段");
                }
                if (StrUtil.isBlank(e.getSplx())) {
                    errorList.add("请填写【审批类型】字段");
                }
                if (StrUtil.isBlank(e.getJszq())) {
                    errorList.add("请填写【建设周期】字段");
                }
                if (CollectionUtil.isNotEmpty(errorList)) {
                    e.setValidateMessage(CollectionUtil.join(errorList, ";"));
                }
            });
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public List<ProgrammeProjectImportDto> importDocuments(MultipartHttpServletRequest request) {
        List<ProgrammeProjectImportDto> excelEntities = ImportExcelUtil.readExcelByRequest(request, new ProgrammeProjectImportDto());
        // 校验excel数据
        validateImportData(excelEntities);
        return excelEntities;
    }

    /**
     * 格式化异构excel元素
     * @param dtos
     * @return
     */
    private List<ProgrammeProjectImportDto> formatHExcelEntities(List<ProgrammeProjectImportDto> dtos) {
        List<ProgrammeProjectImportDto> list = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(dtos)) {
            // 先找出项目名称不为空的数据
            list = dtos.stream().filter(d -> StrUtil.isNotBlank(d.getXmmc())).collect(Collectors.toList());
//            list.stream().reduce(new ProgrammeProjectImportDto(), (r, d) -> {
//                // 如果项目编码长度为16
//                if (StrUtil.length(d.getXmdm()) == PROJECT_CODE_LENGTH) {
//                    // 如果项目代码以X结尾，则获取该代码的前length-2位作为头部编码
//                    if (StrUtil.endWith(d.getXmdm(), PROJECT_CODE_END_WITH)) {
//                        r.setXmdm(StrUtil.subPre(d.getXmdm(), -2));
//                        return r;
//                    }
//                }else if (StrUtil.length(d.getXmdm()) == 2 && NumberUtil.isInteger(d.getXmdm()) &&StrUtil.isNotBlank(r.getXmdm())) {
//                    /**
//                     * 满足以下条件时可以自动补充编码：
//                     * 1.当项目代码长度为2
//                     * 2.可以转化为整形
//                     * 3.遍历对象的xmdm字段不为空
//                     */
//                    DecimalFormat df = new DecimalFormat("00");
//                    String end = df.format(NumberUtil.parseNumber(d.getXmdm()));
//                    d.setXmdm(r.getXmdm() + end);
//                    return r;
//                }
//                r.setXmdm("");
//                return r;
//            });
        }
        return list;
    }

    @Override
    public List<ProgrammeProjectImportDto> importHDocuments(MultipartHttpServletRequest request) {
        ProgrammeProjectImportDto dto = new ProgrammeProjectImportDto();
//        dto.setTitleIndex(4);
        List<ProgrammeProjectImportDto> excelEntities = ImportExcelUtil.readExcelByRequest(request, dto);
        List<ProgrammeProjectImportDto> projectImportDtos = formatHExcelEntities(excelEntities);
        validateImportData(projectImportDtos);
        return projectImportDtos;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int insertBatch(List<ProgrammeProject> list, ImportType importType) {
        if (importType == ImportType.full) {
            ProgrammeProjectExample example = new ProgrammeProjectExample();
            programmeProjectMapper.deleteByExample(example);
        }
        list.stream().forEach(l -> {
            l.setId(IdUtil.fastUUID());
        });
        return savePartition(list);
    }

    /**
     * 分片保存批量数据
     * @param list
     * @return
     */
    private int savePartition(List<ProgrammeProject> list){
        List<List<ProgrammeProject>> partition = Lists.partition(list, MAX_COMMIT_COUNT);
        for (List<ProgrammeProject> p : partition) {
            programmeProjectMapper.insertBatch(p);
        }
        return 1;
    }

    /**
     * 根据excel导入dto将投资匡算明细转为行数据保存
     * @param dto
     * @param calcs
     * @param umsAdmin
     */
    private void setInvestCalcByDto(ProgrammeProjectImportDto dto, List<InvestCalc> calcs, UmsAdmin umsAdmin) {
        if (!Objects.isNull(dto)) {
//            if (!Objects.isNull(dto.getTz2022())) {
//                InvestCalc i = new InvestCalc(dto.getId(), "2022年投资", dto.getTz2022());
//                initInvestCalcInfo(i, umsAdmin);
//                calcs.add(i);
//            }
//            if (!Objects.isNull(dto.getTz2023())) {
//                InvestCalc i = new InvestCalc(dto.getId(), "2023年及以后投资", dto.getTz2023());
//                initInvestCalcInfo(i, umsAdmin);
//                calcs.add(i);
//            }
        }
    }

    /**
     * 数据保存方法（包括项目基本信息与其他关联信息）
     * @param list
     * @param umsAdmin
     * @param taskUnitId
     */
    private void saveBatch(List<ProgrammeProjectImportDto> list, UmsAdmin umsAdmin, String taskUnitId) {
        // 构建项目实体和进度实体
        List<ProgrammeProject> planProjects = new ArrayList<>();
        List<InvestCalc> investCalcs = new ArrayList<>();
        list.stream().forEach(p -> {
            ProgrammeProject programmeProject = new ProgrammeProject();
            BeanUtils.copyProperties(p, programmeProject);
            initProjectInfo(programmeProject, umsAdmin);
            p.setId(programmeProject.getId());
            programmeProject.setTaskUnitId(taskUnitId);
            planProjects.add(programmeProject);
            // 构建项目进度数据
            // setInvestCalcByDto(p, investCalcs, umsAdmin);
        });

        // 保存项目进度数据
        if(CollectionUtil.isNotEmpty(investCalcs)){
            investCalcMapper.insertBatch(investCalcs);
        }
        // 保存项目数据
        savePartition(planProjects);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int insertExcelBatch(List<ProgrammeProjectImportDto> list, UmsAdmin umsAdmin, ImportType importType) {
        if (importType == ImportType.full) {
            ProgrammeProjectExample example = new ProgrammeProjectExample();
            programmeProjectMapper.deleteByExample(example);
        }
        saveBatch(list, umsAdmin, null);
        return 1;
    }

    /**
     * 规划数据关联治理
     */
    private void planLinkValidate(List<ProjectManage> manages) {
        // 查询所有规划-计划关联数据
        List<ProjectManage> list = projectManageMapper.findLinkProject();
        if(CollectionUtil.isNotEmpty(list)) {
            PlanProject planProject = new PlanProject();
            planProject.setHasChild(1);
            List<String> ids = list.stream().map(ProjectManage::getRelId).collect(Collectors.toList());
            PlanProjectExample example = new PlanProjectExample();
            example.createCriteria().andIdIn(ids);
            // 将存在关联关系的规划数据状态置为1
            planProjectMapper.updateByExampleSelective(planProject, example);

            // 将未找到关联关系的条目状态置为error
            // 找到关联关系的条目的关联id设置为relId
            manages.stream().forEach(m -> {
                Optional<ProjectManage> pm = list.stream().filter(p -> StrUtil.equals(p.getId(), m.getProjectId())).findAny();
                if (!pm.isPresent()) {
                    m.setValidateStatus(VALIDATE_STATUS_FAIL);
                    List<String> errorList = new ArrayList<>();
                    errorList.add("未找到匹配的规划项目编码");
                    m.setValidateMessage(CollectionUtil.join(errorList, ";"));
                } else {
                    m.setRelId(pm.get().getRelId());
                }
            });
        }
    }

    /**
     * 校验审批类型
     * @param manages
     */
    private void approveVaildate(List<ProgrammeProject> projectList, List<ProjectManage> manages) {
        List<Dictionary> approves = dictionaryService.findByType("APPROVE_TYPE");
        // 将未找到匹配审批类型的条目状态置为error
        projectList.stream().forEach(p -> {
            boolean match = approves.stream().anyMatch(a -> StrUtil.equals(a.getName(), p.getSplx()));
            Optional<ProjectManage> optional = manages.stream().filter(m -> StrUtil.equals(m.getProjectId(), p.getId())).findAny();
            if (!match&& optional.isPresent()) {
                ProjectManage projectManage = optional.get();
                projectManage.setValidateStatus(VALIDATE_STATUS_FAIL);
                List<String> errorList = new ArrayList<>();
                if (StrUtil.isNotBlank(projectManage.getValidateMessage())){
                    errorList.add(projectManage.getValidateMessage());
                }
                errorList.add("请填写规范的【审批类型】字段");
                projectManage.setValidateMessage(CollectionUtil.join(errorList, ";"));
            }
        });
    }

    /**
     * 校验必填字段
     * @param projectList
     * @param manages
     */
    private void requireValidate(List<ProgrammeProject> projectList, List<ProjectManage> manages) {
        projectList.stream().forEach(p -> {
            Optional<ProjectManage> optional = manages.stream().filter(m -> StrUtil.equals(m.getProjectId(), p.getId())).findAny();
            if (optional.isPresent()){
                ProjectManage projectManage = optional.get();
                List<String> errorList = new ArrayList<>();
                if (StrUtil.isNotBlank(projectManage.getValidateMessage())){
                    errorList.add(projectManage.getValidateMessage());
                }
                if (StrUtil.isBlank(p.getCjdw())) {
                    projectManage.setValidateStatus(VALIDATE_STATUS_FAIL);
                    errorList.add("请填写【建设单位】字段");
                }
                if (StrUtil.isBlank(p.getXmmc())) {
                    projectManage.setValidateStatus(VALIDATE_STATUS_FAIL);
                    errorList.add("请填写【项目名称】字段");
                }
                if (StrUtil.isBlank(p.getXmdm())) {
                    projectManage.setValidateStatus(VALIDATE_STATUS_FAIL);
                    errorList.add("请填写【规划项目编码】字段");
                } else {
                    // 如果项目编码是以X、Y、Z结尾，则需要校验项目编码长度
                    String[] strs = { "X", "Y", "Z" };
                    boolean match = StrUtil.endWithAny(p.getXmdm(), strs);
                    int length = StrUtil.length(p.getXmdm());
                    if (match&&length != PROJECT_CODE_LENGTH) {
                        projectManage.setValidateStatus(VALIDATE_STATUS_FAIL);
                        errorList.add("【规划项目编码】长度不为"+PROJECT_CODE_LENGTH+"位");
                    }
                }
                if (StrUtil.isBlank(p.getJsnr())) {
                    projectManage.setValidateStatus(VALIDATE_STATUS_FAIL);
                    errorList.add("请填写【主要建设内容及使命任务】字段");
                }
                if (Objects.isNull(p.getGhztz())) {
                    projectManage.setValidateStatus(VALIDATE_STATUS_FAIL);
                    errorList.add("请填写【规划总投资】字段");
                }
                if (StrUtil.isBlank(p.getSpqx())) {
                    projectManage.setValidateStatus(VALIDATE_STATUS_FAIL);
                    errorList.add("请填写【审批权限】字段");
                }
                if (StrUtil.isBlank(p.getSplx())) {
                    projectManage.setValidateStatus(VALIDATE_STATUS_FAIL);
                    errorList.add("请填写【审批类型】字段");
                }
                if (StrUtil.isBlank(p.getJszq())) {
                    projectManage.setValidateStatus(VALIDATE_STATUS_FAIL);
                    errorList.add("请填写【建设周期】字段");
                }
                projectManage.setValidateMessage(CollectionUtil.join(errorList, ";"));
            }
        });
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void validateData() {
        PlanProject planProject = new PlanProject();
        planProject.setHasChild(0);
        // 重置规划项目管控数据
        planProjectMapper.updateByExampleSelective(planProject, new PlanProjectExample());
        // 清空关联表，重置关联信息
        projectManageMapper.deleteByExample(new ProjectManageExample());
        // 先查找所有的计划项目数据
        List<ProgrammeProject> projectList = programmeProjectMapper.selectByExampleWithBLOBs(new ProgrammeProjectExample());
        List<ProjectManage> manages = projectList.stream().map(p -> {
            ProjectManage m = new ProjectManage();
            m.setId(IdUtil.fastUUID());
            m.setProjectId(p.getId());
            m.setValidateStatus(VALIDATE_STATUS_SUCCESS);
            return m;
        }).collect(Collectors.toList());
        // 规划代码关联校验
        planLinkValidate(manages);
        // 审批类型校验
        approveVaildate(projectList, manages);
        // 必填字段校验
        requireValidate(projectList, manages);
        // 根据关联规划信息更新部分计划字段（集群名称、工程名称...）
        projectManageMapper.updateInfoByPlan();
        projectManageMapper.updateTbdw();
        projectManageMapper.insertBatch(manages);
    }

    @Override
    public List<ProgrammeProject> findProjectByTaskUnitId(String id) {
        ProgrammeProjectExample example = new ProgrammeProjectExample();
        example.createCriteria().andTaskUnitIdEqualTo(id);
        return programmeProjectMapper.selectByExampleWithBLOBs(example);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void insertTaskBatch(List<ProgrammeProjectImportDto> list, UmsAdmin umsAdmin, ImportType importType, String taskUnitId) {
        if (importType == ImportType.full) {
            ProgrammeProjectExample example = new ProgrammeProjectExample();
            example.createCriteria().andTaskUnitIdEqualTo(taskUnitId);
            programmeProjectMapper.deleteByExample(example);
        }
        // 保存项目信息
        saveBatch(list, umsAdmin, taskUnitId);
        // 更新任务信息
        taskService.updateTaskInfo(taskUnitId);
    }
}
